#pragma once
#include <memory>
#include <type_traits>
#include "card.h"
#include <set>
#include <random>
#include <ctime>
#include <algorithm>

namespace std
{
    template <>
    struct less<dymy::card_t>
    {
        bool
        operator()(const dymy::card_t &__x, const dymy::card_t &__y) const
        {
            return dymy::card::decode_card_num(__x) < dymy::card::decode_card_num(__y);
        }
    };
}
namespace dymy
{

    namespace generator
    {
        // class PersonCards
        // {
        // public:
        //     virtual void FillCards(multiple_card_t &&cards) noexcept {

        //     };
        // };

        multiple_card_t::iterator operator+(const multiple_card_t::iterator &it, card_num_t n);

        template <typename T, card_size_t AN, card_size_t PN, card_size_t EN, card_size_t HN>
        class CardGenerator
        {

        public:
            typedef std::array<card_t, AN> AllCards;

        public:
            CardGenerator(const std::shared_ptr<AllCards> &all_cards_sptr) : all_cards_sptr_(all_cards_sptr) {}
            void MakeCards(std::array<std::unique_ptr<T>, PN> &person, std::vector<card_t> &hole)
            {
                const AllCards &all_cards = *all_cards_sptr_;
                static_assert(AN == PN * EN + HN, "所有卡牌的数量=(人数*平均每人手上的卡牌数量)+底牌数量");
                static_assert(HN % PN == 0, "底牌数量需要为0或者为人数的倍数");

                multiple_card_t result[PN];
                std::default_random_engine e((unsigned int)time(0));
                std::uniform_int_distribution<card_size_t> u_person_index(0, PN - 1);

                constexpr auto AVG = AN / PN;
                for (auto begin = std::cbegin(all_cards); begin != std::cend(all_cards); ++begin)
                {
                    auto person_index = u_person_index(e);
                    while (result[person_index].size() >= AVG)
                    {
                        ++person_index;
                        if (person_index >= PN)
                        {
                            person_index = 0;
                        }
                    }
                    result[person_index].insert(*begin);
                }

                if (HN > 0)
                {
                    constexpr auto for_n = HN / PN;

                    for (auto n = 0; n < for_n; ++n)
                    {
                        std::uniform_int_distribution<card_num_t> u_card_index(0, AVG - n - 1);
                        for (auto p = 0; p < PN; ++p)
                        {
                            card_num_t c_index = u_card_index(e);
                            auto &curr_cards = result[p];
                            auto card_it = curr_cards.begin() + c_index;
                            curr_cards.erase(card_it);
                            hole.push_back(*card_it);
                        }
                    }
                }

                for (card_size_t i = 0; i < PN; ++i)
                {
                    person[i]->FillCards(std::move(result[i]));
                }
            };

        private:
            std::shared_ptr<AllCards> all_cards_sptr_;
        };

    }
}
